#include <stdio.h>

struct frame1 {
  void * fn;
  int sc;

  int arg1;
  int arg2;
  void * ret;
};

struct intwaiter_fp {
  void *fn;
  int sc;

  int waited;
  void *ret;
};
  

void code() {
  struct frame1 * fp = __builtin_ia32_get_cfp();
  printf( "Entering code in thread %d\n", omp_get_thread_num() ); 
  int a = fp->arg1;
  int b = fp->arg2;

  int rmul = a*b;
  int rplus = a+b;

  int rdiv;
  if ( rmul > rplus ) {
    rdiv = rmul/rplus;
  } else {
    rdiv = rplus/rmul;
  }


  struct intwaiter_fp * retframe = fp-> ret;
  retframe->waited = rdiv;

  __builtin_ia32_tdecrease( retframe );
  
  __builtin_ia32_tend();

}


void wait_ret() {
  /* Does nothing here */
  struct intwaiter_fp * waiter = __builtin_ia32_get_cfp();
  printf("Waiter value : %d\n",waiter->waited); 
  __builtin_ia32_tend();
}


#define parallel_execs 100
int main() {
  int a = 5;
  int b = 8;


  struct frame1 *fp_c[parallel_execs];
  for ( int i = 0; i < parallel_execs; ++ i ) 
	fp_c[i] =  __builtin_ia32_tcreate( 2, sizeof(struct frame1) );
  struct intwaiter_fp * waiter[parallel_execs]; 
  for ( int i = 0; i < parallel_execs; ++ i )  {
     waiter[i] =  __builtin_ia32_tcreate(1, sizeof(struct intwaiter_fp) );
     fp_c[i]->fn = code;
     waiter[i]->fn = wait_ret; 

     fp_c[i]-> arg1 = a;
     fp_c[i]-> arg2 = b;
     fp_c[i]->ret =  waiter[i];
 }
  for ( int i = 0; i < parallel_execs; ++ i )  {
  	__builtin_ia32_tdecrease( fp_c[i] );
  	__builtin_ia32_tdecrease( fp_c[i] );
  }
  #pragma omp taskwait
}
